package gov.dhs.cis.soa.readers.reqpro.xmind;

import gov.dhs.cis.soa.readers.reqpro.xmind.XMindObject.TYPE;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;

import org.apache.log4j.Logger;

import com.rational.reqpro.rpx.Application;
import com.rational.reqpro.rpx.AttrValue;
import com.rational.reqpro.rpx._Application;
import com.rational.reqpro.rpx._AttrValues;
import com.rational.reqpro.rpx._Errors;
import com.rational.reqpro.rpx._Project;
import com.rational.reqpro.rpx._Relationship;
import com.rational.reqpro.rpx._Relationships;
import com.rational.reqpro.rpx._Requirement;
import com.rational.reqpro.rpx._Requirements;
import com.rational.reqpro.rpx.enumOpenProjectOptions;
import com.rational.reqpro.rpx.enumProjectFlags;
import com.rational.reqpro.rpx.enumRelatedProjectOptions;
import com.rational.reqpro.rpx.enumRequirementFlags;
import com.rational.reqpro.rpx.enumRequirementLookups;
import com.rational.reqpro.rpx.enumRequirementsWeights;
import com.rational.reqpro.rpx.enumTagFormat;
import com.rational.rjcb.ComObjectProxy;

public class UseCasesReport {
	static final Logger loger = Logger.getLogger(UseCasesReport.class);
	public static final String REQPRO_PROJECT = "C:\\Projects\\ReqPro\\Projects\\USCIS Transformation\\USCIS Transformation.rqs";
	public static final String REQPRO_USER = "admin";
	public static final String REQPRO_PASS = "";

	public static final String LINE_SEP = "\n";
	
	ArrayList<String> toPrint = new ArrayList<String>();
    int nCurrentRow = 0;
    
	_Application RPX = null;
	_Project project = null;
	/*
	 * filter is coma delim and each required UC id is surrounded by square brackets ([]).
	 * example : [UC1], [UC2], [UC20]
	 */
	public XMindObject extractUseCases(String toInclude) {
		XMindObject root = null;
		try {
			RPX = new Application();
			project = RPX.OpenProject(REQPRO_PROJECT,
					enumOpenProjectOptions.eOpenProjOpt_RQSFile, REQPRO_USER,
					REQPRO_PASS, enumProjectFlags.eProjFlag_ReadOnly,
					enumRelatedProjectOptions.eRelatedProjOption_ConnectNone);
//			_Requirements requs = project.GetRequirements("UC", enumRequirementLookups.eReqLookup_Tag, 
//					enumRequirementsWeights.eReqWeight_Medium, enumRequirementFlags.eReqFlag_Empty,
//					200, 40);
			_Requirements requs = project.GetRequirements("UC", enumRequirementLookups.eReqLookup_Tag, 
					enumRequirementsWeights.eReqWeight_Rels, enumRequirementFlags.eReqFlag_Empty,
					200, 40);
			int reqCount = requs.getCount();
			System.out.println("Req Count : " + reqCount);
			int ucCount = 0;
			
			if(reqCount > 0) {
				root = new XMindObject(TYPE.PROJECT, "IOE UC Requirements");
			    requs.MoveFirst();
				_Requirement req = null;
				
				String ucReqNum = "";
				boolean bProcess = false;
				for(int i = 0; ucCount < 1 && i < reqCount; i++) {
					req = requs.GetCurrentRequirement();
					ucReqNum = "[" + req.getReqType().getReqPrefix() + req.getTag(enumTagFormat.eTagFormat_TagRootNumber) + "]";
					//System.out.println(req.getKey());
					if(req.getLevel() == 0) {
						bProcess = true;
						if(toInclude != null && toInclude.indexOf(ucReqNum) < 0) 
							bProcess = false;
						if(bProcess) {
							ucCount++;
							XMindObject sheet = new XMindObject(TYPE.SHEET, req.getTag(enumTagFormat.eTagFormat_FullTag));
							root.addChild(sheet);
							readRequirement(sheet, req);
						}
					}
					requs.MoveNext();
				}
			}
			System.out.println("Total UC count : " + ucCount);
			
			project.CloseProject();
			ComObjectProxy obj = (ComObjectProxy) RPX;
			obj.release();
			RPX= null;			
		} catch (Exception e) {
			try {
				_Errors err = RPX.getErrors();
				System.out.println(err.getAllMessages());
				e.printStackTrace();
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}				
		} finally {
		}
		return root;
	}

	private XMindObject getRequirementAttrs(XMindObject u, _Requirement req) throws Exception {
		_AttrValues types = req.getAttrValues();
		int count = types.getCount();
		if(count <= 0)
			return u;
		//System.out.println("RequirementAttrs# :" + count);
		Enumeration e = types.NewEnum();
		String tempText = LINE_SEP;
		while(e.hasMoreElements()) {
			AttrValue type = new AttrValue(e.nextElement());
			//System.out.println(type.getLabel() + " : " + type.getText());
			if("Management Function".equalsIgnoreCase(type.getLabel())) {
				tempText += type.getText();
			} else if("Increment 1 Identifier".equalsIgnoreCase(type.getLabel())) {
				tempText += type.getText();
			} else if("Planned First Release".equalsIgnoreCase(type.getLabel())) {
				tempText += type.getText();
			} else if("Service Definition".equalsIgnoreCase(type.getLabel())) {
				tempText += ("Yes".equalsIgnoreCase(type.getText()) ? "SD" : "UC");
			} else if("L3 Process".equalsIgnoreCase(type.getLabel())) {
				tempText += type.getText();
			} else if("Working Status".equalsIgnoreCase(type.getLabel())) {
				tempText += type.getText();
				tempText += type.getText();
			}
			tempText += LINE_SEP;
		}
		u.descText += tempText;
		return u;
	}

	public XMindObject getTraceFromList2(XMindObject parent, _Requirement req) throws Exception {
		_Relationships rels = req.getTracesFrom();
		Enumeration<String> relsEnum = rels.NewEnum();
		String relNameStr = "";
		if(rels != null && rels.getCount() > 0) {
			//rels.MoveFirst();
			while(relsEnum.hasMoreElements()) {
				relNameStr = relsEnum.nextElement();
				//System.out.println(" ---" + relNameStr);
				//_Relationship childRel = rels.GetCurrentRelationship();
				//System.out.println(childRel.getRelationshipTypeName() + " = " + childRel.getDestinationKey() + " -> " + childRel.getSourceKey());
				//split..
				int idx = relNameStr.lastIndexOf("}");
				if(idx > 0) {
					String number = relNameStr.substring(idx+1);
					XMindObject relReq = add2LookupList(number /*, rels.GetCurrentRelationship()*/);
					parent.addChild(relReq);
				}
				//add2LookupList(relNameStr /*, rels.GetCurrentRelationship()*/);
				//rels.MoveNext();
			}
		}

		return parent;
	}

	public void getTraceToServDef(String parentTaskKey, _Requirement req, XMindObject xmindObj) throws Exception {
		//ArrayList<String> retList = null;
		_Relationships rels = req.getTracesTo();
		Enumeration<String> relsEnum = rels.NewEnum();
		String relNameStr = "";
//		String ucTag = "";
//		String ucName = "";
//		String ucFullName = "";
		if(rels != null && rels.getCount() > 0) {
			//retList = lookList(parentTaskKey);
			while(relsEnum.hasMoreElements()) {
				relNameStr = relsEnum.nextElement();
				//System.out.println(" ---" + relNameStr);
				//split..
				int idx = relNameStr.indexOf("}");
				if(idx > 0) {
					String number = relNameStr.substring(idx+1, relNameStr.indexOf("{", idx));
					XMindObject servXObj = (XMindObject) servKeysLookup.get(number);
					if(servXObj == null) {
						_Requirement relReq = findReqByKey(number);
						if("SERV".equalsIgnoreCase(relReq.getReqType().getReqPrefix())) {
							System.out.println(relReq.getReqType().getReqPrefix() + " - " + relReq.getName());
							servXObj = createObjFromReq(TYPE.CHILDTOPIC, relReq);
							servKeysLookup.put(number, servXObj);
						}
					} else {
						XMindObject new_servXObj = new XMindObject(servXObj);
						servXObj = new_servXObj;
					}
					if(servXObj != null) {
						xmindObj.addChild(servXObj); 
					}
				}
			}
		}

		return;
	}

	HashMap<String, XMindObject> keysLookup = new HashMap<String, XMindObject>();
	HashMap<String, XMindObject> servKeysLookup = new HashMap<String, XMindObject>();
	
	private XMindObject lookList(String key) {
		XMindObject ret = keysLookup.get(key);
		return ret;
	}
	
	private _Requirement findReqByKey(String key) throws Exception {
		_Requirement relReq = project.GetRequirement(key, enumRequirementLookups.eReqLookup_Key, 
				enumRequirementsWeights.eReqWeight_Medium, enumRequirementFlags.eReqFlag_Empty);
		return relReq;
	}
	
	private XMindObject add2LookupList(String key/*, _Relationship childRel*/) throws Exception {
		XMindObject retObj = lookList(key);
		if(retObj != null)
			return retObj;
		_Requirement relReq = findReqByKey(key);
		retObj = createObjFromReq(TYPE.CHILDTOPIC, relReq);
		keysLookup.put(key, retObj);
		
		String prefix = retObj.prefix;
		if("TASK".equalsIgnoreCase(prefix)) {
			getTraceToServDef(key, relReq, retObj);
		}
		
		return retObj;
	}
	
	private XMindObject createObjFromReq(TYPE objType, _Requirement relReq) throws Exception {
		XMindObject retObj = new XMindObject(objType);
		retObj.id = relReq.getTag(enumTagFormat.eTagFormat_FullTag);
		retObj.name = relReq.getName();
		retObj.descText = relReq.getText();
		retObj.prefix = relReq.getReqType().getReqPrefix();
		return retObj;
	}
	
	public XMindObject readRequirement(XMindObject parReqUC, _Requirement req) throws Exception {
		XMindObject u = createObjFromReq(TYPE.CHILDTOPIC, req);

		if(req.getLevel() == 0) {
			u.objType = TYPE.TOPIC;
			//getRequirementAttrs(u, req);
		} else
			u.objType = TYPE.CHILDTOPIC;
		parReqUC.addChild(u);
		
		u = getTraceFromList2(u, req);

		_Relationships rels = req.getChildren();
		if(rels != null && rels.getCount() > 0) {
			rels.MoveFirst();
			while (!rels.IsEOF()) {
				_Relationship childRel = rels.GetCurrentRelationship();
				_Requirement srcReq = childRel.getDestinationRequirement(0);
				readRequirement(u, srcReq);
				rels.MoveNext();
			}
		}
		return u;
	}	
	

	/**may be dev 
	 * @param args
	 */
	public static void main(String[] args) {
		UseCasesReport pr = new UseCasesReport();
		XMindFileCreator xmindCrt = new XMindFileCreator();
		try {
			String ucInclude = "[UC213]";
			XMindObject xProjectObj = pr.extractUseCases(ucInclude);
			System.out.println("Done");
			xmindCrt.writeAll(xProjectObj);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
